package org.john.auth.client.config;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.john.auth.client.annotation.IgnoreTokenValidate;
import org.john.auth.client.common.AuthClientConst;
import org.john.auth.client.context.Context;
import org.john.auth.client.context.UserContext;
import org.john.auth.client.context.UserRedisContext;
import org.john.auth.client.exception.ExpiredTokenException;
import org.john.auth.client.exception.UnauthorizedException;
import org.john.auth.client.util.JwtTokenUtil;
import org.john.auth.client.util.RequestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

	@Autowired
	private RedisTemplate redisTemplate;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		String requestUri = request.getRequestURI();
		log.debug("RequestURL: {}", request.getRequestURL().toString());

		// 通过注解判断是否需要做健全操作
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		Class<?> targetClass = method.getDeclaringClass();
		boolean ignoreTokenValidate = targetClass.isAnnotationPresent(IgnoreTokenValidate.class) || method.isAnnotationPresent(IgnoreTokenValidate.class);

		if (!ignoreTokenValidate) {
			String token = RequestUtil.getToken(request);
			if (StringUtils.isNotEmpty(token)) {
				try {
					// 解析token
					// 1、判断token是否失效
					UserContext userContext = JwtTokenUtil.paseUserContext(token);
					// 2、判断redis中token是否存在
					UserRedisContext value = (UserRedisContext) redisTemplate.opsForValue().get(AuthClientConst.KEY_REDIS_TOKEN_PREFIX + userContext.getUniqueId());
					if (value == null || !value.isEffective()) {
						// 如果redis中token失效返回给前端token已失效
						throw new ExpiredTokenException();
					}
					Context.setUserContext(userContext);
				} catch (ExpiredJwtException e) {
					// token失效处理
					// 1、删除redis中失效token
					UserContext userContext = JwtTokenUtil.paseUserContext(e.getClaims());
					redisTemplate.opsForValue().getOperations().delete(AuthClientConst.KEY_REDIS_TOKEN_PREFIX + userContext.getUniqueId());
					// 2、返回前端token失效
					throw new ExpiredTokenException();
				}
			} else {
				throw new UnauthorizedException();
			}
		}
		return true;
	}
}